
package kvsnode;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.Future;

/**
 * This is a node which is represented as a stub in RMI registry.
 * 
 * - related instruction in the instruction document -
 * 
 * Storage and retrieval of values for specific keys in the system (that is,
 * communication between the system and the outside world) is carried out by
 * means of RMI calls; the goal here is that if a client can find any individual
 * node in the system and make an RMI call on it, it can store or retrieve the
 * data for any key supported by the system. This means that it is possible that
 * multiple stores to the same key will occur "simultaneously"; in such
 * situations, as long as one of the stored values ends up stored, your system
 * will be considered to work correctly. Note that such RMI calls will likely
 * result in asynchronous communication occurring within the system (to retrieve
 * the requested value, or to store a new value) before a response can be
 * generated; this may require some thread synchronization.
 * 
 * @author cy
 * @version 5/13/2013
 */
public interface KVSNode extends Remote
{

  /**
   * The name of Remote Registry (fake) inside the real registry.
   */
  String REMOTE_REGISTRY = "RemoteRegistry";

  /**
   * A length of the BlockedQueue to put the clients in the queue until the
   * session is available.
   */
  int QUEUE_LENGTH_FOR_CHANNELS = 100;

  /**
   * A length of TransferQueue which converges the queues for each channels.
   */
  int QUEUE_LENGTH_FOR_MAIN_TRANSFER_CHANNEL = 1000;

  /**
   * Alive time of the idle thread in seconds.
   */
  int ALIVE_SEC_OF_IDLE_THREAD = 10;

  /**
   * Run the node.
   * 
   * @throws RemoteException if there is a problem completing the method call.
   */
  void runNode() throws RemoteException;

  /**
   * Send a String query from a client to the node.
   * 
   * @param the_message a string message.
   * @throws RemoteException if there is a problem completing the method call.
   * @return a Future object which will have the value of the query.
   */
  Future<Object> sendQuery(String the_message) throws RemoteException;

  /**
   * This method is to send a message to the node having this method from
   * another node.
   * 
   * - related instruction in the instruction document -
   * 
   * The keys in the system are Strings, and the values are arbitrary
   * Serializable objects (so that they can be sent/received using RMI). Each
   * key is mapped (hashed) to one (and only one) of the 2^m nodes; more than
   * one key may (and almost certainly will) be mapped to the same node, as
   * there are far more possible Strings than nodes. You can devise any method
   * you like to perform the mapping; for the purposes of these assignments, the
   * "quality" of your hashing algorithm is not important. Ideally, it would be
   * uniform: 1/2^m of the entire possible key space would be mapped to each
   * node.
   * 
   * @param the_source_node_id a node id from departure
   * @param the_dest_port_id a port number the message should be delivered.
   * @param the_message a message to process.
   * @throws RemoteException if there is a problem completing the method call.
   */
  void sendMessage(int the_source_node_id, int the_dest_port_id, Object the_message)
    throws RemoteException;

  /**
   * Give data to an actual node with the node IDs which another actual node
   * takes care of, so the actual node importing the data can generate virtual
   * nodes which take the responsibilities the previous actual and virtual nodes
   * have done.
   * 
   * - related instruction in the instruction document -
   * 
   * An actual node can leave the system at any time, either in an orderly
   * fashion (by notifying other nodes as appropriate) or by "crashing"
   * (becoming unresponsive). When this happens, the other actual nodes must
   * eventually detect it and rebalance. For the purposes of these assignments
   * you may assume that an actual node leaving the ring in an orderly fashion
   * always stays in the ring long enough for its data to be reallocated to
   * other actual nodes; that is, it does not leave the ring until it knows
   * leaving is "safe". You may not assume anything about how many actual nodes
   * leave the system, when they leave, or how they leave.
   * 
   * @throws RemoteException if there is a problem completing the method call.
   * @param the_node_data_map node id and data pairs from an actual node.
   * @return true if this node import the data successfully, by the true return
   *         value, the caller knows that it is safe to leave the ring.
   */
  boolean importData(Map<Integer, Collection<Object>> the_node_data_map)
    throws RemoteException;

  /**
   * When this method is invoked by a new actual node which tries to join in the
   * ring, an virtual node pass the data it has been storing to the new node by
   * the return values. However, if this method is invoked in existing actual
   * node, it returns signal (may be null).
   * 
   * - related instruction in the instruction document -
   * 
   * A new actual node can join the system at any time when the system has less
   * than 2^m actual nodes. When a new actual node joins the system, it takes an
   * available number (currently being simulated by another actual node) and
   * informs some other nodes in the system (by sending messages appropriately).
   * When this happens, the nodes rebalance such that they all simulate
   * appropriate sets of nodes and all store appropriate key/value pairs. Such
   * rebalancing should be as localized as possible; adding one actual node to a
   * 1024-node ring with a nontrivial number of existing actual nodes should not
   * affect every other actual node on the ring. You can devise any method you
   * like to perform this rebalancing. For the purposes of these assignments you
   * may assume that, when an actual node is added to the system, you always
   * have sufficient time to complete your rebalancing before another actual
   * node is added to the system.
   * 
   * @param the_node_id a node id to request.
   * @throws RemoteException if there is a problem completing the method call.
   * @return the list of node IDs which should be generated in the server.
   *         Return happens after rebalancing in the requested actual node.
   */
  Collection<Object> exportData(int the_node_id) throws RemoteException;

  /**
   * Returns the actual node id for this node. If it is actual node, then it
   * returns its id.
   * 
   * @throws RemoteException if there is a problem completing the method call.
   * @return the actual node id for this node.
   */
  Integer getActualNodeForThisNode() throws RemoteException;

}
